package com.example.JavaWebApi.core.apiinterceptors;

import com.alibaba.fastjson.JSON;
import com.example.JavaWebApi.core.apiinterceptors.annotation.AllowAnonymous;
import com.example.JavaWebApi.core.apiinterceptors.annotation.Authorize;
import com.example.JavaWebApi.core.commonmodel.ResponseModel;
import com.example.JavaWebApi.core.commonmodel.ResponseTypeEnum;
import com.example.JavaWebApi.core.httpcontext.HttpContextHelper;
import com.example.JavaWebApi.core.ip.IpHelper;
import com.example.JavaWebApi.core.jwthelper.JwtHelper;
import com.example.JavaWebApi.core.jwthelper.Tuple;
import com.example.JavaWebApi.model.entity.systemEntity.Userinfo;
import com.example.JavaWebApi.model.vo.systemVo.ControllerDescription;
import com.example.JavaWebApi.service.systemService.IApiRoleService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @PROJECT_NAME: JavaWebApi
 * @DESCRIPTION: JWT鉴权验证处理
 * @Author: YangZe
 * @DATE: 2021/11/28 14:18
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {
    private static final String HEADER_NAME="Authorization";
    @Autowired
    private IApiRoleService apiRoleService;
    @Override
    public boolean preHandle(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse, @NotNull Object object) throws NoSuchAlgorithmException {
        //不进入控制器内部方法的请求全部允许
        if (!(object instanceof HandlerMethod)) {
            return true;
        }
        //获取ip
        RequestHeaderContext.setIPContext(IpHelper.GetUserIp(httpServletRequest));
        String token = httpServletRequest.getHeader(HEADER_NAME);
        if (token != null) {
            token = token.replace("Bearer ", "");
            RequestHeaderContext.setAuthorizeContext(token, false);
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        Class<?> controllerClass = handlerMethod.getBeanType();
        //方法上标记AllowAnonymous 直接放行
        if (method.isAnnotationPresent(AllowAnonymous.class)) {
            return true;
        }
        Authorize authorize;
        //类上标记鉴权
        if (controllerClass.isAnnotationPresent(Authorize.class)) {
            if (method.isAnnotationPresent(Authorize.class)) {
                authorize=method.getAnnotation(Authorize.class);
                return authorizeHandler(httpServletRequest,httpServletResponse,authorize,controllerClass,method,httpServletRequest.getMethod());
            }
            else {
                authorize=controllerClass.getAnnotation(Authorize.class);
                return authorizeHandler(httpServletRequest,httpServletResponse,authorize,controllerClass,method,httpServletRequest.getMethod());
            }

        }
        else {
            if(!method.isAnnotationPresent(Authorize.class)){
                return true;
            }
            else {
                authorize=method.getAnnotation(Authorize.class);
                return authorizeHandler(httpServletRequest,httpServletResponse,authorize,controllerClass,method,httpServletRequest.getMethod());
            }
        }

    }
    @Override
    public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, @Nullable Exception ex) throws Exception{
        RequestHeaderContext.clean();
    }
    /**
     * Description: 鉴权处理
     * @param httpServletRequest
     * @param httpServletResponse
     * @param annotation
     * @return boolean 是否成功
     * @author 杨泽
     * @date 2022/10/12 14:28
     */
    private boolean authorizeHandler(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Authorize annotation,Class<?> controllerClass,Method method,String requestMethod) throws NoSuchAlgorithmException {
        String token=httpServletRequest.getHeader(HEADER_NAME);
        if (token == null){
            returnJson(httpServletResponse,401,ResponseTypeEnum.NoToken);
            return false;
        }
        else {
            //先判断有没有Bearer关键字
            if (token.contains("Bearer")) {
                //获取token并把token之前的Bearer 给替换了
                token = token.replace("Bearer ", "");
                Tuple<Boolean, ResponseTypeEnum> res = JwtHelper.verifyToken(token, annotation);
                if (!res.getItem()) {
                    returnJson(httpServletResponse, 403, res.getItem1());
                }
                //存放token
                RequestHeaderContext.removeAuthorizeContext();
                RequestHeaderContext.setAuthorizeContext(token, true);
                if(annotation.validApi()){
                    Userinfo userinfo= RequestHeaderContext.getUserinfo();
                    if(userinfo.getId()>0){
                        ControllerDescription.ApiDescription apiDescription=new ControllerDescription.ApiDescription();
                        apiDescription.setParent(controllerClass.getName());
                        apiDescription.setName(method.getName());
                        //List<Annotation> annotationList= Arrays.stream(method.getAnnotations()).flatMap(t->Arrays.stream(t.annotationType().getAnnotations())).collect(Collectors.toList());
                        apiDescription.setMethod(requestMethod);
                        List<String> result= apiRoleService.getRoleApi(userinfo.getRoleIdList(), Collections.singletonList(apiDescription.getId()));

                    }

                }

                return res.getItem();
            } else {
                returnJson(httpServletResponse, 401, ResponseTypeEnum.IllegalToken);
                return false;
            }
        }
    }

    private void returnJson(HttpServletResponse httpServletResponse,int code,ResponseTypeEnum responseTypeEnum){
        PrintWriter writer = null;
        ResponseModel responseModel=new ResponseModel(responseTypeEnum,null);
        String r= JSON.toJSONString(responseModel);
        httpServletResponse.setStatus(code);
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json");
        try {
            writer= httpServletResponse.getWriter();
            writer.print(r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
